﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Multithreading多线程
{
    /// <summary>
    /// 委托多线程代码演示
    /// 现在.net core 还没有支持BeginInvoke
    /// </summary>
    public static class DelegationDoem
    {
        /// <summary>
        /// 初识异步委托多线程
        /// 这里我们可以看出来我们的同步方法的速度比异步要慢
        /// 异步执行是一个无序性的，不知道哪一个先执行后执行
        /// 但是线程也不是越多越来，因为我们线程越多占有的资源越多，所以适当的使用才是最好的
        /// </summary>
        public static void Show()
        {
            //我们启动一个无返回参数的委托
            Action<int> action = Running;
            Console.WriteLine("执行代码之前的时间毫秒数：" + DateTime.Now.Millisecond);
            //我们正常启动同步代码
            for (int i = 0; i < 5; i++)
            {
                action(i);
            }
            Console.WriteLine("执行代码同步之后的时间毫秒数：" + DateTime.Now.Millisecond);
            //我们启动5个线程
            for (int i = 0; i < 5; i++)
            {
                action.BeginInvoke(i, (x) =>
                {
                    Console.WriteLine("执行代码异步之后的时间毫秒数：" + DateTime.Now.Millisecond);
                }, i);
            }
            Console.WriteLine("一切结束啦");
            Console.ReadLine();
        }

        /// <summary>
        /// 异步执行返回值回调
        /// BeginInvoke至少有两个参数，第一个是异步回调委托它接受的是异步回调方法的返回值
        /// 第二个是当前委托的状态，当我们定义异步委托可以带上这个状态参数，分辨
        /// </summary>
        public static void ReturnData()
        {
            //创建一个异步返回值
            IAsyncResult returnData = null;
            //创建一个委托
            Func<int> func = Running;
            //创建异步委托回调
            AsyncCallback asyncCallback = x =>
            {
                //判断异步回调的参数是不是等于委托异步的返回值：结果是的
                Console.WriteLine("判断回调参数是不是异步方法返回值：" + object.ReferenceEquals(x, returnData));
                //获取线程标识值
                Console.WriteLine("回调参数：" + x.AsyncState);
                //我们可以使用EndInvoke堵塞异步委托
                Console.WriteLine("等待返回参数:" + func.EndInvoke(x));
            };
            //执行委托异步方法
            returnData = func.BeginInvoke(asyncCallback, "我是状态");
            Console.ReadLine();
        }

        /// <summary>
        /// 异步执行返回值回调。
        /// IsCompleted 判断当前线程是否完成。
        /// 但是这里会卡主线程，卡界面。
        /// </summary>
        public static void ReturnData1()
        {
            //创建一个委托
            Func<int> func = Running;
            //执行委托异步
            IAsyncResult returnData = func.BeginInvoke(null, "我是状态");
            int i = 0;
            //我们使用IsCompleted判断异步委托是否完成，但是会堵塞主线程
            //可以做上传进度条
            while (!returnData.IsCompleted)
            {
                if (i % 10 == 0)
                {
                    Console.WriteLine("文件上传进度：" + i + "%");
                }
                else if (i == 100)
                {
                    Console.WriteLine("文件上传进度完成：" + i + "%");
                }
                i++;
                //线程等待
                Thread.Sleep(100);
            }
            Console.ReadLine();
        }

        /// <summary>
        /// 异步执行返回值回调。
        /// 同时我们也可以获取当前的线程任何进行堵塞
        /// </summary>
        public static void ReturnData2()
        {
            Func<int> func = Running;
            IAsyncResult returnData = func.BeginInvoke(null, "我是状态");
            //堵塞线程，直到执行完之后才往下走
            returnData.AsyncWaitHandle.WaitOne();
            //堵塞线程，直到执行完之后才往下走
            returnData.AsyncWaitHandle.WaitOne(-1);
            //堵塞线程，但是我们最多等待1秒钟
            returnData.AsyncWaitHandle.WaitOne(1000);
            Console.ReadLine();
        }

        /// <summary>
        /// 一个执行需要长时间的任务
        /// </summary>
        static void Running(int s)
        {
            Console.WriteLine("**********************************");
            Console.WriteLine("执行开始啦" + s);
            Console.WriteLine("获取当前执行的线程ID：" + Thread.CurrentThread.ManagedThreadId.ToString());
            var j = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                j++;
            }
            Console.WriteLine("执行结束啦" + s);
        }

        /// <summary>
        /// 一个执行需要长时间的任务
        /// </summary>
        static int Running()
        {
            Console.WriteLine("**********************************");
            Console.WriteLine("执行开始啦");
            Console.WriteLine("获取当前执行的线程ID："+Thread.CurrentThread.ManagedThreadId.ToString());
            var j = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                j++;
            }
            Console.WriteLine("执行结束啦");
            return j;
        }
    }
}
